package com.example.project.utils;

import cn.hutool.core.io.FileTypeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.example.project.constant.Constants;
import com.example.project.vo.model.Result;
import com.example.project.vo.model.SaveFile;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.zip.ZipFile;

import static com.example.project.constant.Constants.SYSTEM_NAME;

public class FileMangerUtils {

    private static String avatar = "Avatar";
    private static String picture = "Picture";

    private static final int BUFFER_SIZE = 4 * 1024;

    /**
     * @param paths path路径
     */
    public static void downLoad(HttpServletResponse response, List<String> paths) throws IOException, ExecutionException, InterruptedException {


        Boolean isOneFile = false;
        String compressFiles = "";
        String fileName = null;
        File tempFile = null;

        if (paths.size() > 1) {
            isOneFile = false;

            compressFiles = FileZipCompressUtils.compressMergeOnlyFile(paths, Constants.PROJECT_ROOT_DIRECTORY);
            tempFile = new File(compressFiles);
            ZipFile zipFile = new ZipFile(compressFiles);
            if (zipFile.size() <= 0) {
                response.setHeader("res", Base64.encodeBase64String(JSON.toJSONString(Result.fail("文件不存在")).getBytes(StandardCharsets.UTF_8)));
                tempFile.delete();
                return;
            }
            fileName = tempFile.getName();


        } else {
            tempFile = new File(Constants.PROJECT_ROOT_DIRECTORY + paths.get(0));
            if (!tempFile.exists()) {
                response.setHeader("res", Base64.encodeBase64String(JSON.toJSONString(Result.fail("文件不存在")).getBytes(StandardCharsets.UTF_8)));
                return;
            }
            isOneFile = true;
            fileName = tempFile.getName();

        }

        response.setContentType("application/octet-stream;charset=utf-8");
        response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
        // 设置编码
        response.setCharacterEncoding("UTF-8");
        InputStream inputStream = Files.newInputStream(tempFile.toPath());
        OutputStream outputStream = response.getOutputStream();
        byte[] buff = new byte[2048];
        int len = 0;
        while ((len = inputStream.read(buff)) > 0) {
            outputStream.write(buff, 0, len);
            outputStream.flush();
        }
        inputStream.close();

        // 如果不是单文件就是zip
        if (!isOneFile) {
            tempFile.delete();
        }
    }

    public static String importEasyFile(MultipartFile file)throws IOException{
        String dirPath = Constants.PROJECT_ROOT_DIRECTORY + Constants.SYSTEM_NAME + "/";
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String fileName =  IdWorker.getId()+file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
        File pictureFile = new File(dirPath + fileName);
        file.transferTo(pictureFile);
        return "http://127.0.0.1:9091/files/"+fileName;
    }



    /**
     * 进行实时nginxUrl的替换
     *
     * @param datas 需要传入被修改的值
     */
//    public static <T> void dealNginx(List<T> datas) {
//
//        if (!ObjectUtils.isEmpty(datas)) {
//            for (int i = 0; i < datas.size(); i++) {
//                T t = datas.get(i);
//                String getMethodName = "get" + avatar;
//                Method getMethod = null;
//                try {
//                    getMethod = t.getClass().getMethod(getMethodName, new Class[]{});
//
//                    String fileArrayString = InvokeUtils.getMethodValue(getMethod, t);
//                    String setMethodName = "set" + avatar;
//                    if (StringUtils.isEmpty(fileArrayString)) {
//                        getMethodName = "get" + picture;
//                        getMethod = t.getClass().getMethod(getMethodName, new Class[]{});
//                        fileArrayString = InvokeUtils.getMethodValue(getMethod, t);
//                        setMethodName = "set" + picture;
//                    }
//                    Method setMethod = t.getClass().getMethod(setMethodName, String.class);
//
//
//                    //开始处理 array
//                    JSONArray fileOriArray = JSONArray.parseArray(fileArrayString);
//                    for (int j = 0; j < fileOriArray.size(); j++) {
//                        // 开始处理 object
//                        JSONObject fileObject = fileOriArray.getJSONObject(j);
//                        String fileUrl = nginxUrl + mvcPath + fileObject.get("fileObjectName").toString();
//                        fileObject.remove("fileUrl");
//                        fileObject.put("fileUrl", fileUrl);
//                    }
//                    String fileArrayJson = fileOriArray.toJSONString();
//                    //塞值回去
//                    InvokeUtils.setMethodValue(setMethod, t, fileArrayJson);
//                } catch (Exception e) {
//                    throw new ServiceException("反射出现异常！");
//                }
//            }
//        }
//    }


    /**
     * @param files
     * @return jsonArray
     */
    public static String importFiles(MultipartFile[] files) throws IOException {
        JSONArray jsonArray = new JSONArray();
        for (MultipartFile file : files) {
            SaveFile saveFile = createSaveFile(file);
            upLoad(saveFile, file);
            jsonArray.add(saveFile);
        }
        String jsonString = JSONObject.toJSONString(jsonArray);
        return jsonString;
    }


    /**
     * 文件上传
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static void upLoad(SaveFile saveFile, MultipartFile file) throws IOException {
        String dirPath = Constants.PROJECT_ROOT_DIRECTORY + saveFile.getFileBucket() + "/";
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File pictureFile = new File(dirPath + saveFile.getFileObjectName());
        System.out.println("文件存储地址=》"+pictureFile);
        file.transferTo(pictureFile);
    }

    public static SaveFile createSaveFile(MultipartFile file) {
        long byteSize = file.getSize();
        Long kbSize = byteSize / 1024;
        String fileOriginName = file.getOriginalFilename();
        String fileCode = String.valueOf(System.currentTimeMillis());
        String fileSuffix = fileOriginName.substring(fileOriginName.indexOf("."));
        String fileObjectName = fileCode + fileSuffix;
        String secretFlag = "N";
        String fileBucket = SYSTEM_NAME;
        String fileUrl = "/files/" + fileObjectName;
        Integer fileVersion = 1;
        String fileSizeInfo = kbSize + "kb";
        Long fileSizeKb = kbSize;
        // Integer fileType = getFileType(file);

        SaveFile saveFile = SaveFile.builder().fileOriginName(fileOriginName).fileCode(fileCode).fileSuffix(fileSuffix).fileObjectName(fileObjectName)
                .secretFlag(secretFlag)
                .fileBucket(fileBucket)
                .fileUrl(fileUrl)
                .fileVersion(fileVersion)
                .fileSizeInfo(fileSizeInfo)
               // .fileType(fileType)
                .fileSizeKb(fileSizeKb).build();
        return saveFile;
    }


    public static Integer getFileType(MultipartFile file) {
        InputStream inputStream = null;
        String type = null;
        try {
            inputStream = file.getInputStream();
            type = FileTypeUtil.getType(inputStream);


            if (type.equalsIgnoreCase("JPG") || type.equalsIgnoreCase("JPEG")
                    || type.equalsIgnoreCase("GIF") || type.equalsIgnoreCase("PNG")
                    || type.equalsIgnoreCase("BMP") || type.equalsIgnoreCase("PCX")
                    || type.equalsIgnoreCase("TGA") || type.equalsIgnoreCase("PSD")
                    || type.equalsIgnoreCase("TIFF")) {
                return 1;
            }
            if (type.equalsIgnoreCase("mp3") || type.equalsIgnoreCase("OGG")
                    || type.equalsIgnoreCase("WAV") || type.equalsIgnoreCase("REAL")
                    || type.equalsIgnoreCase("APE") || type.equalsIgnoreCase("MODULE")
                    || type.equalsIgnoreCase("MIDI") || type.equalsIgnoreCase("VQF")
                    || type.equalsIgnoreCase("CD")) {
                return 2;
            }
            if (type.equalsIgnoreCase("mp4") || type.equalsIgnoreCase("avi")
                    || type.equalsIgnoreCase("MPEG-1") || type.equalsIgnoreCase("RM")
                    || type.equalsIgnoreCase("ASF") || type.equalsIgnoreCase("WMV")
                    || type.equalsIgnoreCase("qlv") || type.equalsIgnoreCase("MPEG-2")
                    || type.equalsIgnoreCase("MPEG4") || type.equalsIgnoreCase("mov")
                    || type.equalsIgnoreCase("3gp")) {
                return 3;
            }
            if (type.equalsIgnoreCase("doc") || type.equalsIgnoreCase("docx")
                    || type.equalsIgnoreCase("ppt") || type.equalsIgnoreCase("pptx")
                    || type.equalsIgnoreCase("xls") || type.equalsIgnoreCase("xlsx")
                    || type.equalsIgnoreCase("zip") || type.equalsIgnoreCase("jar")) {
                return 4;
            }
            if (type.equalsIgnoreCase("txt")) {
                return 4;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }


    public static void downLoadDir(HttpServletResponse response, String rootPath) throws IOException, ExecutionException, InterruptedException {
        rootPath = Constants.PROJECT_ROOT_DIRECTORY + rootPath + "\\";

        String fileName = "project";
        String compressFiles = FileZipCompressUtils.compressToDirs(Collections.singletonList(rootPath), fileName);


        ZipFile zipFile = new ZipFile(compressFiles);
        if (zipFile.size() == 0) {
            response.setHeader("res", URLEncoder.encode(JSON.toJSONString(Result.fail("无文件")), "UTF-8"));
            return;
        }
        File tempFile = new File(compressFiles);
        fileName = fileName + ".zip";

        response.setContentType("application/x-zip-compressed;charset=utf-8");
        // 设置编码
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));

        InputStream inputStream = Files.newInputStream(tempFile.toPath());
        OutputStream outputStream = response.getOutputStream();
        byte[] buff = new byte[2048];
        int len = 0;
        while ((len = inputStream.read(buff)) > 0) {
            outputStream.write(buff, 0, len);
            outputStream.flush();
        }
        inputStream.close();

        // 删除临时文件
        tempFile.delete();


    }


    public static void chunkDownload(String range, HttpServletRequest request, HttpServletResponse response) {

        //要下载的文件
        File file = new File(System.getProperty("user.dir") + "\\pom.xml");


        long startByte = 0;
        long endByte = file.length() - 1;

        //有range的话  说明不是第一次进行请求
        if (range != null && range.contains("bytes=") && range.contains("-")) {
            range = range.substring(range.lastIndexOf("=") + 1).trim();
            String ranges[] = range.split("-");
            try {
                //根据range解析下载分片的位置区间
                if (ranges.length == 1) {
                    //情况1，如：bytes=-1024  从开始字节到第1024个字节的数据
                    if (range.startsWith("-")) {
                        endByte = Long.parseLong(ranges[0]);
                    }
                    //情况2，如：bytes=1024-  第1024个字节到最后字节的数据
                    else if (range.endsWith("-")) {
                        startByte = Long.parseLong(ranges[0]);
                    }
                }
                //情况3，如：bytes=1024-2048  第1024个字节到2048个字节的数据
                else if (ranges.length == 2) {
                    startByte = Long.parseLong(ranges[0]);
                    endByte = Long.parseLong(ranges[1]);
                }

            } catch (NumberFormatException e) {
                startByte = 0;
                endByte = file.length() - 1;
            }
        }

        long contentLength = endByte - startByte + 1;
        String fileName = file.getName();
        //文件类型
        String contentType = request.getServletContext().getMimeType(fileName);

        //响应头设置
        //  重要 Accept-Ranges： 表示响应标识支持范围请求，字段的具体值用于定义范围请求的单位，如：bytes。当发现Accept-Range  头时，可以尝试继续之前中断的下载，而不是重新开始。
        response.setHeader("Accept-Ranges", "bytes");
        //Content-Type 表示资源类型，如：文件类型
        response.setHeader("Content-Type", contentType);
        //Content-Disposition 表示响应内容以何种形式展示，是以内联的形式（即网页或者页面的一部分），还是以附件的形式下载并保存到本地。
        // 这里文件名换成下载后你想要的文件名，inline表示内联的形式，即：浏览器直接下载
        response.setHeader("Content-Disposition", "inline;filename=pom.xml");
        //Content-Length 表示资源内容长度，即：当前下载文件大小
        response.setHeader("Content-Length", String.valueOf(contentLength));
        //Content-Range 表示响应了多少数据，格式为：[要下载的开始位置]-[结束位置]/[文件总大小]  bytes 0-1024/8081
        response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + file.length());

        response.setStatus(response.SC_OK);
        response.setContentType(contentType);

        BufferedOutputStream outputStream = null;
        RandomAccessFile randomAccessFile = null;
        //已传送数据大小
        long transmitted = 0;
        try {
            randomAccessFile = new RandomAccessFile(file, "r");
            outputStream = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[2048];
            int len = 0;
            randomAccessFile.seek(startByte);
            //判断是否到了最后不足2048（buff的length）个byte
            while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) {
                outputStream.write(buff, 0, len);
                transmitted += len;
            }
            //处理不足buff.length部分
            if (transmitted < contentLength) {
                len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted));
                outputStream.write(buff, 0, len);
                transmitted += len;
            }

            outputStream.flush();
            response.flushBuffer();
            randomAccessFile.close();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (randomAccessFile != null) {
                    randomAccessFile.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static void chunkUpload(String range, MultipartFile file, HttpServletRequest request, HttpServletResponse response) {


    }
}

